"""
语音合成API接口
"""

from fastapi import APIRouter, HTTPException, status, Depends, BackgroundTasks
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
from io import BytesIO
import asyncio
import os
import uuid
from datetime import datetime

from ...core.exceptions import (
    ValidationError, 
    TTSSError, 
    NotFoundError,
    with_error_handling
)
from ...core.security import (
    get_current_user,
    get_current_user_optional,
    rate_limit,
    require_permission
)
from ...core.logging import audit_logger
from ...services.tts import (
    tts_service,
    TTSRequest,
    VoiceProfile,
    VoiceSettings,
    AudioFormat
)


# 创建路由
router = APIRouter()


# 请求模型
class TTSRequestModel(BaseModel):
    """TTS请求模型"""
    text: str = Field(..., min_length=1, max_length=10000, description="要合成的文本")
    voice_id: Optional[str] = Field(None, description="语音ID")
    voice_preset: Optional[str] = Field(None, description="语音预设")
    rate: Optional[int] = Field(200, ge=50, le=500, description="语速")
    volume: Optional[float] = Field(0.9, ge=0.0, le=1.0, description="音量")
    pitch: Optional[int] = Field(50, ge=0, le=100, description="音调")
    format: Optional[str] = Field("wav", pattern="^(wav|mp3|ogg|flac)$", description="音频格式")
    sample_rate: Optional[int] = Field(22050, ge=8000, le=48000, description="采样率")
    apply_effects: Optional[bool] = Field(False, description="是否应用音频效果")
    effects_config: Optional[Dict[str, Any]] = Field(None, description="音频效果配置")


class BatchTTSRequestModel(BaseModel):
    """批量TTS请求模型"""
    texts: List[str] = Field(..., min_items=1, max_items=100, description="文本列表")
    voice_id: Optional[str] = Field(None, description="语音ID")
    voice_preset: Optional[str] = Field(None, description="语音预设")
    format: Optional[str] = Field("wav", pattern="^(wav|mp3|ogg|flac)$", description="音频格式")


class VoiceProfileModel(BaseModel):
    """语音配置模型"""
    name: str = Field(..., min_length=1, max_length=100, description="语音名称")
    language: str = Field(..., min_length=2, max_length=10, description="语言代码")
    gender: str = Field(..., pattern="^(male|female|neutral)$", description="性别")
    engine: str = Field("pyttsx3", description="TTS引擎")
    settings: Optional[Dict[str, Any]] = Field(None, description="语音设置")


class VoiceSettingsModel(BaseModel):
    """语音设置模型"""
    rate: int = Field(200, ge=50, le=500, description="语速")
    volume: float = Field(0.9, ge=0.0, le=1.0, description="音量")
    pitch: int = Field(50, ge=0, le=100, description="音调")
    emphasis: float = Field(1.0, ge=0.5, le=2.0, description="重音强度")
    pause_duration: float = Field(0.5, ge=0.0, le=5.0, description="停顿时长")
    breathing: bool = Field(False, description="是否添加呼吸声")


# 响应模型
class TTSResponseModel(BaseModel):
    """TTS响应模型"""
    success: bool
    message: str
    audio_url: Optional[str] = None
    duration: Optional[float] = None
    format: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None


class VoiceInfoModel(BaseModel):
    """语音信息模型"""
    id: str
    name: str
    language: str
    gender: str
    engine: str
    settings: Optional[Dict[str, Any]] = None


# API端点
@router.post("/synthesize", response_model=TTSResponseModel)
@with_error_handling("synthesize_text")
async def synthesize_text(
    request: TTSRequestModel,
    background_tasks: BackgroundTasks,
):
    """语音合成"""
    try:
        # 检查TTS服务状态
        if not tts_service.is_initialized:
            raise TTSSError("TTS服务未初始化")
        
        # 获取语音配置
        voice_profile = None
        if request.voice_id:
            voices = await tts_service.get_available_voices()
            voice_profile = next((v for v in voices if v.id == request.voice_id), None)
            if not voice_profile:
                raise ValidationError(f"语音ID {request.voice_id} 不存在")
        
        # 应用语音预设
        voice_settings = None
        if request.voice_preset:
            if not await tts_service.set_voice_preset(request.voice_preset):
                raise ValidationError(f"语音预设 {request.voice_preset} 不存在")
            voice_settings = tts_service.voice_controller.settings
        
        # 创建TTS请求
        # 将字符串格式转换为AudioFormat枚举
        audio_format = AudioFormat.WAV  # 默认格式
        format_map = {
            "wav": AudioFormat.WAV,
            "mp3": AudioFormat.MP3,
            "ogg": AudioFormat.OGG,
            "flac": AudioFormat.FLAC
        }
        if request.format.lower() in format_map:
            audio_format = format_map[request.format.lower()]
        
        tts_request = TTSRequest(
            text=request.text,
            voice_profile=voice_profile,
            rate=request.rate,
            volume=request.volume,
            pitch=request.pitch,
            format=audio_format,
            sample_rate=request.sample_rate
        )
        
        # 执行语音合成 - 修复字符串和枚举的处理
        try:
            response = await tts_service.synthesize(
                text=request.text,
                voice_profile=voice_profile,
                voice_settings=voice_settings,
                output_format=request.format.lower(),  # 传递字符串而非枚举
                apply_effects=request.apply_effects,
                effects_config=request.effects_config
            )
        except Exception as e:
            raise TTSSError(f"语音合成失败: {str(e)}")
        
        if not response.success:
            raise TTSSError(response.error_message or "语音合成失败")
        
        # 保存音频文件（后台任务）
        audio_url = await _save_audio_file(response.audio_data, request.format, background_tasks)
        
        return TTSResponseModel(
            success=True,
            message="语音合成成功",
            audio_url=audio_url,
            duration=response.duration,
            format=request.format,
            metadata=response.metadata
        )
        
    except Exception as e:
        if isinstance(e, (ValidationError, TTSSError)):
            raise
        raise TTSSError(f"语音合成失败: {str(e)}")


@router.post("/synthesize/batch", response_model=List[TTSResponseModel])
@with_error_handling("synthesize_batch")
@rate_limit(limit=5, window=60)  # 每分钟5次批量请求
@require_permission("batch_synthesis")
async def synthesize_batch(
    request: BatchTTSRequestModel,
    background_tasks: BackgroundTasks,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """批量语音合成"""
    # 记录审计日志
    audit_logger.log_user_action(
        user_id=current_user.get("sub"),
        action="synthesize_batch",
        resource="tts",
        details={"text_count": len(request.texts), "format": request.format}
    )
    
    try:
        # 检查TTS服务状态
        if not tts_service.is_initialized:
            raise TTSSError("TTS服务未初始化")
        
        # 获取语音配置
        voice_profile = None
        if request.voice_id:
            voices = await tts_service.get_available_voices()
            voice_profile = next((v for v in voices if v.id == request.voice_id), None)
        
        # 批量合成
        responses = await tts_service.batch_synthesize(
            text_list=request.texts,
            voice_profile=voice_profile,
            output_format=request.format
        )
        
        results = []
        for i, response in enumerate(responses):
            if response.success:
                audio_url = await _save_audio_file(response.audio_data, request.format, background_tasks)
                results.append(TTSResponseModel(
                    success=True,
                    message=f"第{i+1}个文本合成成功",
                    audio_url=audio_url,
                    duration=response.duration,
                    format=request.format,
                    metadata=response.metadata
                ))
            else:
                results.append(TTSResponseModel(
                    success=False,
                    message=f"第{i+1}个文本合成失败: {response.error_message}"
                ))
        
        return results
        
    except Exception as e:
        if isinstance(e, (ValidationError, TTSSError)):
            raise
        raise TTSSError(f"批量语音合成失败: {str(e)}")


@router.get("/voices", response_model=List[VoiceInfoModel])
@with_error_handling("get_voices")
async def get_voices(
    engine: Optional[str] = None
):
    """获取可用语音列表"""
    try:
        voices = await tts_service.get_available_voices(engine)
        
        return [
            VoiceInfoModel(
                id=voice.id,
                name=voice.name,
                language=voice.language,
                gender=voice.gender,
                engine=voice.engine,
                settings=voice.settings
            )
            for voice in voices
        ]
        
    except Exception as e:
        raise TTSSError(f"获取语音列表失败: {str(e)}")


@router.get("/presets", response_model=Dict[str, Any])
@with_error_handling("get_presets")
async def get_presets(
    current_user: Optional[Dict[str, Any]] = Depends(get_current_user_optional)
):
    """获取语音预设列表"""
    try:
        presets = tts_service.get_voice_presets()
        
        result = {}
        for name, settings in presets.items():
            result[name] = {
                "rate": settings.rate,
                "volume": settings.volume,
                "pitch": settings.pitch,
                "emphasis": settings.emphasis,
                "pause_duration": settings.pause_duration,
                "breathing": settings.breathing
            }
        
        return result
        
    except Exception as e:
        raise TTSSError(f"获取语音预设失败: {str(e)}")


@router.post("/presets/{preset_name}")
@with_error_handling("apply_preset")
@rate_limit(limit=20, window=60)
async def apply_preset(
    preset_name: str,
    current_user: Optional[Dict[str, Any]] = Depends(get_current_user_optional)
):
    """应用语音预设"""
    try:
        success = await tts_service.set_voice_preset(preset_name)
        
        if not success:
            raise ValidationError(f"语音预设 {preset_name} 不存在")
        
        # 记录审计日志（如果有用户信息）
        if current_user:
            audit_logger.log_user_action(
                user_id=current_user.get("sub"),
                action="apply_preset",
                resource="tts",
                details={"preset": preset_name}
            )
        
        return {
            "success": True,
            "message": f"语音预设 {preset_name} 应用成功",
            "current_settings": tts_service.voice_controller.settings.__dict__
        }
        
    except Exception as e:
        if isinstance(e, ValidationError):
            raise
        raise TTSSError(f"应用语音预设失败: {str(e)}")


@router.post("/voices", response_model=VoiceInfoModel)
@with_error_handling("create_voice_profile")
@require_permission("manage_voices")
async def create_voice_profile(
    voice_data: VoiceProfileModel,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """创建自定义语音配置"""
    try:
        # 创建语音配置
        voice_profile = VoiceProfile(
            id=f"custom_{len(await tts_service.get_available_voices()) + 1}",
            name=voice_data.name,
            language=voice_data.language,
            gender=voice_data.gender,
            engine=voice_data.engine,
            settings=voice_data.settings
        )
        
        # 这里应该保存到数据库，简化处理
        # 实际实现需要数据库集成
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="create_voice_profile",
            resource="tts",
            details={"voice_name": voice_data.name}
        )
        
        return VoiceInfoModel(
            id=voice_profile.id,
            name=voice_profile.name,
            language=voice_profile.language,
            gender=voice_profile.gender,
            engine=voice_profile.engine,
            settings=voice_profile.settings
        )
        
    except Exception as e:
        raise TTSSError(f"创建语音配置失败: {str(e)}")


@router.get("/engines")
@with_error_handling("get_engines")
async def get_engines(
    current_user: Optional[Dict[str, Any]] = Depends(get_current_user_optional)
):
    """获取可用TTS引擎"""
    try:
        engines = tts_service.get_available_engines()
        current_engine = tts_service.get_current_engine()
        
        return {
            "available_engines": engines,
            "current_engine": current_engine,
            "is_initialized": tts_service.is_initialized
        }
        
    except Exception as e:
        raise TTSSError(f"获取TTS引擎失败: {str(e)}")


@router.post("/engines/{engine_name}")
@with_error_handling("switch_engine")
@require_permission("manage_engines")
async def switch_engine(
    engine_name: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """切换TTS引擎"""
    try:
        success = await tts_service.switch_engine(engine_name)
        
        if not success:
            raise ValidationError(f"TTS引擎 {engine_name} 不可用")
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="switch_engine",
            resource="tts",
            details={"engine": engine_name}
        )
        
        return {
            "success": True,
            "message": f"TTS引擎切换到 {engine_name}",
            "current_engine": engine_name
        }
        
    except Exception as e:
        if isinstance(e, ValidationError):
            raise
        raise TTSSError(f"切换TTS引擎失败: {str(e)}")


@router.get("/info")
@with_error_handling("get_tts_info")
async def get_tts_info():
    """获取TTS服务信息"""
    try:
        return {
            "service_initialized": tts_service.is_initialized,
            "current_engine": tts_service.get_current_engine(),
            "available_engines": tts_service.get_available_engines(),
            "supported_formats": ["wav", "mp3", "ogg", "flac"],
            "voice_presets": list(tts_service.get_voice_presets().keys())
        }
        
    except Exception as e:
        raise TTSSError(f"获取TTS信息失败: {str(e)}")


# 辅助函数
async def _save_audio_file(audio_data: bytes, format: str, background_tasks: BackgroundTasks) -> str:
    """保存音频文件并返回URL"""
    from ...core.config import settings
    
    # 生成唯一文件名
    timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
    unique_id = str(uuid.uuid4())[:8]
    filename = f"tts_{timestamp}_{unique_id}.{format}"
    
    # 保存文件路径
    file_path = os.path.join(settings.AUDIO_CACHE_DIR, filename)
    
    # 保存文件
    def save_file():
        with open(file_path, 'wb') as f:
            f.write(audio_data)
    
    background_tasks.add_task(save_file)
    
    # 返回正确的URL (修正为与路由匹配的URL)
    return f"/api/v1/tts/audio/{filename}"


def _get_audio_file_path(filename: str) -> str:
    """获取音频文件完整路径"""
    from ...core.config import settings
    return os.path.join(settings.AUDIO_CACHE_DIR, filename)


@router.get("/audio/{filename}", summary="获取音频文件", description="下载指定的音频文件（无需认证）")
@with_error_handling("get_audio_file")
async def get_audio_file(
    filename: str
):
    """
    获取音频文件 - 无需认证
    
    - **filename**: 音频文件名
    
    返回:
    - 音频文件流
    
    可能的错误:
    - 404: 文件不存在
    - 500: 服务器内部错误
    """
    from ...core.logging import logger
    
    try:
        file_path = _get_audio_file_path(filename)
        
        logger.info(f"尝试访问音频文件: {filename}")
        logger.debug(f"完整文件路径: {file_path}")
        
        if not os.path.exists(file_path):
            logger.warning(f"音频文件不存在: {filename}")
            raise NotFoundError(f"音频文件 {filename} 不存在")
        
        # 获取文件大小
        file_size = os.path.getsize(file_path)
        logger.info(f"音频文件 {filename} 大小: {file_size} bytes")
        
        # 获取文件内容
        try:
            with open(file_path, 'rb') as f:
                audio_data = f.read()
        except IOError as e:
            logger.error(f"读取音频文件 {filename} 失败: {str(e)}")
            raise TTSSError(f"读取音频文件失败: {str(e)}")
        
        # 确定MIME类型
        ext = os.path.splitext(filename)[1].lower()
        mime_types = {
            '.wav': 'audio/wav',
            '.mp3': 'audio/mpeg',
            '.ogg': 'audio/ogg',
            '.flac': 'audio/flac'
        }
        mime_type = mime_types.get(ext, 'application/octet-stream')
        
        logger.info(f"返回音频文件 {filename}, 内容类型: {mime_type}")
        
        return StreamingResponse(
            BytesIO(audio_data),
            media_type=mime_type,
            headers={
                "Content-Disposition": f"inline; filename={filename}",
                "Content-Length": str(len(audio_data))
            }
        )
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            # 已经记录了日志，直接抛出
            raise
        
        # 记录未预期的错误
        logger.error(f"获取音频文件 {filename} 时发生未预期错误: {str(e)}", exc_info=True)
        raise TTSSError(f"获取音频文件失败: {str(e)}")
